package sdedit;

import com.google.common.base.Objects;
import com.google.common.collect.Iterables;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.xtend2.lib.StringConcatenation;
import org.eclipse.xtext.generator.IFileSystemAccess;
import org.eclipse.xtext.xbase.lib.Exceptions;
import org.eclipse.xtext.xbase.lib.IteratorExtensions;
import sdmakerz_v1.coresyntax.SDMakerV1RuntimeModule;
import sdmakerz_v1.coresyntax.SDMakerV1Utils;
import sdmakerz_v1.coresyntax.generator.ContextImpl;
import sdmakerz_v1.coresyntax.generator.DiagramRefDataImpl;
import sdmakerz_v1.coresyntax.generator.interfaces.IConfigData;
import sdmakerz_v1.coresyntax.generator.interfaces.IContext;
import sdmakerz_v1.coresyntax.generator.interfaces.IDiagramRefData;
import sdmakerz_v1.coresyntax.generator.interfaces.IInputData;
import sdmakerz_v1.coresyntax.generator.interfaces.ISDMakerModelLevelGen;
import sdmakerz_v1.coresyntax.sDMakerV1.Actor;
import sdmakerz_v1.coresyntax.sDMakerV1.Alt;
import sdmakerz_v1.coresyntax.sDMakerV1.Alternant;
import sdmakerz_v1.coresyntax.sDMakerV1.Binding;
import sdmakerz_v1.coresyntax.sDMakerV1.Call;
import sdmakerz_v1.coresyntax.sDMakerV1.CombinableDiagramElement;
import sdmakerz_v1.coresyntax.sDMakerV1.Config;
import sdmakerz_v1.coresyntax.sDMakerV1.Consequent;
import sdmakerz_v1.coresyntax.sDMakerV1.Diagram;
import sdmakerz_v1.coresyntax.sDMakerV1.DiagramElement;
import sdmakerz_v1.coresyntax.sDMakerV1.DiagramRef;
import sdmakerz_v1.coresyntax.sDMakerV1.Eval;
import sdmakerz_v1.coresyntax.sDMakerV1.Import;
import sdmakerz_v1.coresyntax.sDMakerV1.Loop;
import sdmakerz_v1.coresyntax.sDMakerV1.Obj;
import sdmakerz_v1.coresyntax.sDMakerV1.Opt;
import sdmakerz_v1.coresyntax.sDMakerV1.Reference;
import sdmakerz_v1.coresyntax.sDMakerV1.SDMakerModel;
import sdmakerz_v1.coresyntax.sDMakerV1.Type;

/**
 * La classe principale de generation vers SDEDIT
 * 
 * @author pstl-team
 */
@SuppressWarnings("all")
public class SDMakerToSDEditGen implements ISDMakerModelLevelGen {
  /**
   * On conserve une liste des noms d'acteurs et objets deja declare
   * pour eviter des declarations redondantes.
   */
  private List<String> alreadyDeclared;
  
  /**
   * indique utiliser pour eviter la generation de beaucoup de ligne blanche
   * lors de la generation de diagramme (voir la methode correspondante)
   */
  private boolean whiteLineSet;
  
  public boolean canHandle(final Resource input) {
    boolean canHandle = false;
    TreeIterator<EObject> _allContents = input.getAllContents();
    Iterable<EObject> _iterable = IteratorExtensions.<EObject>toIterable(_allContents);
    for (final EObject eo : _iterable) {
      if ((eo instanceof SDMakerModel)) {
        canHandle = true;
      }
    }
    return canHandle;
  }
  
  public void doGenerate(final IContext context, final IFileSystemAccess fsa) {
    try {
      IInputData inputData = context.getInputData();
      Resource input = inputData.getInput();
      ArrayList<String> _arrayList = new ArrayList<String>();
      this.alreadyDeclared = _arrayList;
      this.whiteLineSet = false;
      TreeIterator<EObject> _allContents = input.getAllContents();
      Iterable<EObject> _iterable = IteratorExtensions.<EObject>toIterable(_allContents);
      Iterable<Diagram> _filter = Iterables.<Diagram>filter(_iterable, Diagram.class);
      for (final Diagram d : _filter) {
        {
          ContextImpl _contextImpl = new ContextImpl();
          ContextImpl c = _contextImpl;
          Class<? extends IConfigData> _bindIConfigData = SDMakerV1RuntimeModule.bindIConfigData();
          IConfigData config = _bindIConfigData.newInstance();
          Class<? extends IDiagramRefData> _bindIDiagramRefData = SDMakerV1RuntimeModule.bindIDiagramRefData();
          IDiagramRefData refData = _bindIDiagramRefData.newInstance();
          config.init(null);
          String _name = d.getName();
          refData.init(d, null, null, _name);
          c.setInput(inputData);
          c.setConfigData(config);
          c.setDiagramRefData(refData);
          String _outputBasedName = inputData.getOutputBasedName();
          String _plus = ("sdedit-gen/" + _outputBasedName);
          String _plus_1 = (_plus + "_");
          String _name_1 = d.getName();
          String _plus_2 = (_plus_1 + _name_1);
          String _plus_3 = (_plus_2 + ".sd");
          CharSequence _compileSDEditDiagram = this.compileSDEditDiagram(d, c);
          fsa.generateFile(_plus_3, _compileSDEditDiagram);
        }
      }
    } catch (Exception _e) {
      throw Exceptions.sneakyThrow(_e);
    }
  }
  
  public CharSequence compileSDEditDiagram(final Diagram d, final ContextImpl c) {
    CharSequence _xblockexpression = null;
    {
      StringConcatenation _builder = new StringConcatenation();
      CharSequence charSequenceResult = _builder;
      StringConcatenation _builder_1 = new StringConcatenation();
      {
        EList<DiagramElement> _diagram_elts = d.getDiagram_elts();
        Iterable<Actor> _filter = Iterables.<Actor>filter(_diagram_elts, Actor.class);
        for(final Actor elt : _filter) {
          CharSequence _compileActor = this.compileActor(elt, c);
          _builder_1.append(_compileActor, "");
          _builder_1.newLineIfNotEmpty();
        }
      }
      {
        EList<DiagramElement> _diagram_elts_1 = d.getDiagram_elts();
        Iterable<Obj> _filter_1 = Iterables.<Obj>filter(_diagram_elts_1, Obj.class);
        for(final Obj elt_1 : _filter_1) {
          CharSequence _compileObj = this.compileObj(elt_1, c);
          _builder_1.append(_compileObj, "");
          _builder_1.newLineIfNotEmpty();
        }
      }
      charSequenceResult = _builder_1;
      boolean _equals = (this.whiteLineSet == false);
      if (_equals) {
        this.whiteLineSet = true;
        StringConcatenation _builder_2 = new StringConcatenation();
        _builder_2.append("           ");
        _builder_2.newLine();
        _builder_2.append("           ");
        _builder_2.newLine();
        String _plus = (charSequenceResult + _builder_2.toString());
        charSequenceResult = _plus;
      }
      StringConcatenation _builder_3 = new StringConcatenation();
      {
        EList<DiagramElement> _diagram_elts_2 = d.getDiagram_elts();
        for(final DiagramElement elt_2 : _diagram_elts_2) {
          CharSequence _compile = this.compile(elt_2, c);
          _builder_3.append(_compile, "");
          _builder_3.newLineIfNotEmpty();
        }
      }
      String _plus_1 = (charSequenceResult + _builder_3.toString());
      CharSequence _charSequenceResult = charSequenceResult = _plus_1;
      _xblockexpression = (_charSequenceResult);
    }
    return _xblockexpression;
  }
  
  public CharSequence compile(final DiagramElement elt, final ContextImpl c) {
    CharSequence _switchResult = null;
    boolean _matched = false;
    if (!_matched) {
      if (elt instanceof Call) {
        final Call _call = (Call)elt;
        _matched=true;
        CharSequence _compileCall = this.compileCall(_call, c);
        _switchResult = _compileCall;
      }
    }
    if (!_matched) {
      if (elt instanceof Alt) {
        final Alt _alt = (Alt)elt;
        _matched=true;
        CharSequence _compileAlt = this.compileAlt(_alt, c);
        _switchResult = _compileAlt;
      }
    }
    if (!_matched) {
      if (elt instanceof Loop) {
        final Loop _loop = (Loop)elt;
        _matched=true;
        CharSequence _compileLoop = this.compileLoop(_loop, c);
        _switchResult = _compileLoop;
      }
    }
    if (!_matched) {
      if (elt instanceof Opt) {
        final Opt _opt = (Opt)elt;
        _matched=true;
        CharSequence _compileOpt = this.compileOpt(_opt, c);
        _switchResult = _compileOpt;
      }
    }
    if (!_matched) {
      if (elt instanceof DiagramRef) {
        final DiagramRef _diagramRef = (DiagramRef)elt;
        _matched=true;
        CharSequence _compileDiagramRef = this.compileDiagramRef(_diagramRef, c);
        _switchResult = _compileDiagramRef;
      }
    }
    if (!_matched) {
      if (elt instanceof Actor) {
        final Actor _actor = (Actor)elt;
        _matched=true;
        StringConcatenation _builder = new StringConcatenation();
        _switchResult = _builder;
      }
    }
    if (!_matched) {
      if (elt instanceof Obj) {
        final Obj _obj = (Obj)elt;
        _matched=true;
        StringConcatenation _builder = new StringConcatenation();
        _switchResult = _builder;
      }
    }
    if (!_matched) {
      if (elt instanceof Import) {
        final Import _import = (Import)elt;
        _matched=true;
        StringConcatenation _builder = new StringConcatenation();
        _switchResult = _builder;
      }
    }
    if (!_matched) {
      if (elt instanceof Config) {
        final Config _config = (Config)elt;
        _matched=true;
        StringConcatenation _builder = new StringConcatenation();
        _switchResult = _builder;
      }
    }
    if (!_matched) {
      if (elt instanceof Eval) {
        final Eval _eval = (Eval)elt;
        _matched=true;
        StringConcatenation _builder = new StringConcatenation();
        _switchResult = _builder;
      }
    }
    if (!_matched) {
      if (elt instanceof Binding) {
        final Binding _binding = (Binding)elt;
        _matched=true;
        StringConcatenation _builder = new StringConcatenation();
        _switchResult = _builder;
      }
    }
    if (!_matched) {
      StringConcatenation _builder = new StringConcatenation();
      _builder.append("not_supported");
      _switchResult = _builder;
    }
    return _switchResult;
  }
  
  public CharSequence compileOpt(final Opt opt, final ContextImpl c) {
    StringConcatenation _builder = new StringConcatenation();
    _builder.append("[c:opt]");
    _builder.newLine();
    {
      EList<CombinableDiagramElement> _opts = opt.getOpts();
      for(final CombinableDiagramElement elt : _opts) {
        _builder.append("    ");
        CharSequence _compile = this.compile(elt, c);
        _builder.append(_compile, "    ");
        _builder.newLineIfNotEmpty();
      }
    }
    _builder.append("[/c]");
    _builder.newLine();
    return _builder;
  }
  
  public CharSequence compileLoop(final Loop loop, final ContextImpl c) {
    StringConcatenation _builder = new StringConcatenation();
    _builder.append("[c:loop]");
    _builder.newLine();
    {
      EList<CombinableDiagramElement> _body = loop.getBody();
      for(final CombinableDiagramElement elt : _body) {
        _builder.append("    ");
        CharSequence _compile = this.compile(elt, c);
        _builder.append(_compile, "    ");
        _builder.newLineIfNotEmpty();
      }
    }
    _builder.append("[/c]");
    _builder.newLine();
    return _builder;
  }
  
  public CharSequence compileAlt(final Alt alt, final ContextImpl c) {
    StringConcatenation _builder = new StringConcatenation();
    _builder.append("[c:alt]");
    _builder.newLine();
    {
      Consequent _conseq = alt.getConseq();
      EList<CombinableDiagramElement> _conseq_elts = _conseq.getConseq_elts();
      for(final CombinableDiagramElement elt : _conseq_elts) {
        _builder.append("    ");
        CharSequence _compile = this.compile(elt, c);
        _builder.append(_compile, "    ");
        _builder.newLineIfNotEmpty();
      }
    }
    {
      EList<Alternant> _alters = alt.getAlters();
      for(final Alternant alter : _alters) {
        _builder.append("--[else]");
        _builder.newLine();
        {
          EList<CombinableDiagramElement> _alter_elts = alter.getAlter_elts();
          for(final CombinableDiagramElement elt_1 : _alter_elts) {
            _builder.append("    ");
            CharSequence _compile_1 = this.compile(elt_1, c);
            _builder.append(_compile_1, "    ");
            _builder.newLineIfNotEmpty();
          }
        }
      }
    }
    _builder.append("[/c]");
    _builder.newLine();
    return _builder;
  }
  
  public CharSequence compileCall(final Call call, final ContextImpl c) {
    CharSequence _xblockexpression = null;
    {
      IDiagramRefData _diagramRefData = c.getDiagramRefData();
      String _caller = call.getCaller();
      String callerName = _diagramRefData.getNewName(_caller);
      IDiagramRefData _diagramRefData_1 = c.getDiagramRefData();
      String _called = call.getCalled();
      String calledName = _diagramRefData_1.getNewName(_called);
      StringConcatenation _builder = new StringConcatenation();
      _builder.append(callerName, "");
      _builder.append(":");
      _builder.append(calledName, "");
      _builder.append(".");
      String _name = call.getName();
      _builder.append(_name, "");
      _builder.append("()");
      _builder.newLineIfNotEmpty();
      {
        EList<CombinableDiagramElement> _nested_calls = call.getNested_calls();
        boolean _notEquals = (!Objects.equal(_nested_calls, null));
        if (_notEquals) {
          {
            EList<CombinableDiagramElement> _nested_calls_1 = call.getNested_calls();
            for(final CombinableDiagramElement e : _nested_calls_1) {
              CharSequence _compile = this.compile(e, c);
              _builder.append(_compile, "");
              _builder.newLineIfNotEmpty();
            }
          }
        }
      }
      _xblockexpression = (_builder);
    }
    return _xblockexpression;
  }
  
  public CharSequence compileActor(final Actor actor, final ContextImpl c) {
    StringConcatenation _builder = new StringConcatenation();
    CharSequence charSequenceResult = _builder;
    IDiagramRefData _diagramRefData = c.getDiagramRefData();
    String _name = actor.getName();
    String actorName = _diagramRefData.getNewName(_name);
    boolean _contains = SDMakerV1Utils.contains(this.alreadyDeclared, actorName);
    boolean _equals = (_contains == false);
    if (_equals) {
      this.alreadyDeclared.add(actorName);
      StringConcatenation _builder_1 = new StringConcatenation();
      _builder_1.append(actorName, "");
      _builder_1.append(":Actor");
      _builder_1.newLineIfNotEmpty();
      charSequenceResult = _builder_1;
    }
    return charSequenceResult;
  }
  
  public CharSequence compileObj(final Obj obj, final ContextImpl c) {
    StringConcatenation _builder = new StringConcatenation();
    CharSequence charSequenceResult = _builder;
    IDiagramRefData _diagramRefData = c.getDiagramRefData();
    String _name = obj.getName();
    String objName = _diagramRefData.getNewName(_name);
    boolean _contains = SDMakerV1Utils.contains(this.alreadyDeclared, objName);
    boolean _equals = (_contains == false);
    if (_equals) {
      this.alreadyDeclared.add(objName);
      StringConcatenation _builder_1 = new StringConcatenation();
      _builder_1.append(objName, "");
      _builder_1.append(": ");
      Type _type = obj.getType();
      String _identifier = _type.getIdentifier();
      _builder_1.append(_identifier, "");
      _builder_1.newLineIfNotEmpty();
      charSequenceResult = _builder_1;
    }
    return charSequenceResult;
  }
  
  public CharSequence compileDiagramRef(final DiagramRef diagramRef, final ContextImpl c) {
    StringConcatenation _builder = new StringConcatenation();
    CharSequence charSequenceResult = _builder;
    IDiagramRefData oldRefData = c.getDiagramRefData();
    DiagramRefDataImpl _diagramRefDataImpl = new DiagramRefDataImpl();
    DiagramRefDataImpl newRefData = _diagramRefDataImpl;
    Diagram d = null;
    Reference _ref = diagramRef.getRef();
    Diagram _findDiagram = c.findDiagram(_ref);
    d = _findDiagram;
    IDiagramRefData _diagramRefData = c.getDiagramRefData();
    String _name = d.getName();
    newRefData.init(d, diagramRef, _diagramRefData, _name);
    c.setDiagramRefData(newRefData);
    CharSequence _compileSDEditDiagram = this.compileSDEditDiagram(d, c);
    charSequenceResult = _compileSDEditDiagram;
    c.setDiagramRefData(oldRefData);
    return charSequenceResult;
  }
}
